# Part of DTCloud. See LICENSE file for full copyright and licensing details.

import json
import logging


import dtcloud
import dtcloud.modules.registry
from dtcloud import http
from dtcloud.exceptions import AccessError
from dtcloud.http import request
from dtcloud.service import security
from dtcloud.tools import ustr
from dtcloud.tools.translate import _
# TODO(amos): add
from dtcloud.release import product_name

from .utils import ensure_db, _get_login_redirect_url, is_user_internal


_logger = logging.getLogger(__name__)


# Shared parameters for all login/signup flows
SIGN_UP_REQUEST_PARAMS = {'db', 'login', 'debug', 'token', 'message', 'error', 'scope', 'mode',
                          'redirect', 'redirect_hostname', 'email', 'name', 'partner_id',
                          'password', 'confirm_password', 'city', 'country_id', 'lang', 'signup_email'}
LOGIN_SUCCESSFUL_PARAMS = set()


#:::访问static静态文件
# TODO(amos): amos add
import os
from jinja2 import Environment, FileSystemLoader
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
templateLoader = FileSystemLoader(searchpath=BASE_DIR + "/static/src/templates")
env = Environment(loader=templateLoader)


class Home(http.Controller):

    @http.route('/', type='http', auth="none")
    def index(self, s_action=None, db=None, **kw):
        if request.db and request.session.uid and not is_user_internal(request.session.uid):
            return request.redirect_query('/web/login_successful', query=request.params)
        return request.redirect_query('/web', query=request.params)

    # ideally, this route should be `auth="user"` but that don't work in non-monodb mode.
    @http.route('/web', type='http', auth="none")
    def web_client(self, s_action=None, **kw):

        # Ensure we have both a database and a user
        ensure_db()
        if not request.session.uid:
            return request.redirect_query('/web/login', query=request.params, code=303)
        if kw.get('redirect'):
            return request.redirect(kw.get('redirect'), 303)
        if not security.check_session(request.session, request.env):
            raise http.SessionExpiredException("Session expired")
        if not is_user_internal(request.session.uid):
            return request.redirect('/web/login_successful', 303)

        # Side-effect, refresh the session lifetime
        request.session.touch()

        # Restore the user on the environment, it was lost due to auth="none"
        request.update_env(user=request.session.uid)
        try:
            context = request.env['ir.http'].webclient_rendering_context()
            response = request.render('web.webclient_bootstrap', qcontext=context)
            response.headers['X-Frame-Options'] = 'DENY'
            return response
        except AccessError:
            return request.redirect('/web/login?error=access')

    @http.route('/web/webclient/load_menus/<string:unique>', type='http', auth='user', methods=['GET'])
    def web_load_menus(self, unique, lang=None):
        """
        Loads the menus for the webclient
        :param unique: this parameters is not used, but mandatory: it is used by the HTTP stack to make a unique request
        :param lang: language in which the menus should be loaded (only works if language is installed)
        :return: the menus (including the images in Base64)
        """
        if lang:
            request.update_context(lang=lang)

        menus = request.env["ir.ui.menu"].load_web_menus(request.session.debug)
        body = json.dumps(menus, default=ustr)
        response = request.make_response(body, [
            # this method must specify a content-type application/json instead of using the default text/html set because
            # the type of the route is set to HTTP, but the rpc is made with a get and expects JSON
            ('Content-Type', 'application/json'),
            ('Cache-Control', 'public, max-age=' + str(http.STATIC_CACHE_LONG)),
        ])
        return response

   # TODO(amos): add
    @http.route('/web/assets/load_menus/<string:unique>', type='http', auth='user', methods=['GET'])
    def web_assets_load_menus(self, unique, lang=None):
        if unique == '1234':
            return self._get_menus(request)

        if lang:
            request.update_context(lang=lang)

        menus = request.env["ir.ui.menu"].load_web_menus(request.session.debug)
        body = json.dumps(menus, default=ustr)
        response = request.make_response(body, [
            # this method must specify a content-type application/json instead of using the default text/html set because
            # the type of the route is set to HTTP, but the rpc is made with a get and expects JSON
            ('Content-Type', 'application/json'),
            ('Cache-Control', 'public, max-age=' + str(http.STATIC_CACHE_LONG)),
        ])
        return response


    # TODO(amos): add
    def _get_menus(self, request):
        """
        自定义用户菜单
        增缓存变量
        SQL查询，权限绑定
        """
        cr, uid, context, pool = request.cr, request.session.uid, request.context, request.env
        limenus = ''

        #:::查询所有菜单

        menus = pool['ir.ui.menu'].load_web_menus(request.session.debug)
        root = menus.get('root')
        # root_menu = pool['ir.ui.menu'].sudo().search([('parent_id', '=', False)], order="sequence, id desc", limit=50)

        #一级模板:只有一个节点
        menu1 = """<li>
                        <a href="#menu_id=%s&amp;action=%s">
                            %s
                            <span>%s</span>
                        </a>
                   </li>"""
        #如果有下一个执行新的模板
        menu1_children = """<li><a href="javascript: void(0);"  class="has-arrow">
                                    %s
                                    <span>%s</span>
                                </a> <ul class="sub-menu" aria-expanded="false">%s</ul></li>"""

        for line in root.get('children'):
            #判断一级是否有下级

            node1 = menus.get(line).get('children')

            if node1:
                node_html = ''
                node_html += self._get_node1(node1,menus)

                font_icon = ''
                if menus.get(line).get('font_icon'):
                    font_icon = '<i class="%s"></i>' % menus.get(line).get('font_icon')

                limenus += menu1_children % (font_icon,menus.get(line).get('name'),node_html)

            else:
                font_icon = ''
                if menus.get(line).get('font_icon'):
                    font_icon = '<i class="%s"></i>' % menus.get(line).get('font_icon')
                limenus += menu1 % (menus.get(line).get('id'),menus.get(line).get('actionID'),font_icon,menus.get(line).get('name'))

        data = {
            "menus": limenus,
        }
        return json.dumps(data)

    # TODO(amos): add

    def _get_node1(self,node1,menus):
        """
        用户第一个节点
        """
        limenus = ''
        #一级模板:只有一个节点
        menu1 = """<li>
                        <a href="#menu_id=%s&amp;action=%s">
                           %s
                            <span>%s</span>
                        </a>
                   </li>"""
        #如果有下一个执行新的模板
        menu1_children = """<li><a href="javascript: void(0);"  class="has-arrow">
                                    %s
                                    <span>%s</span>
                                </a> <ul class="sub-menu" aria-expanded="false">%s</ul></li>"""
        for line in node1:
            node1 = menus.get(line).get('children')
            if node1:
                node_html = ''
                node_html += self._get_node1(node1, menus)

                font_icon = ''
                if menus.get(line).get('font_icon'):
                    font_icon = '<i class="%s"></i>' % menus.get(line).get('font_icon')

                limenus += menu1_children % (font_icon, menus.get(line).get('name'), node_html)
            else:
                font_icon = ''
                if menus.get(line).get('font_icon'):
                    font_icon = '<i class="%s"></i>' % menus.get(line).get('font_icon')
                limenus += menu1 % (menus.get(line).get('id'),menus.get(line).get('actionID'),font_icon,menus.get(line).get('name'))


        return limenus



    def _login_redirect(self, uid, redirect=None):
        return _get_login_redirect_url(uid, redirect)

    @http.route('/web/login', type='http', auth="none")
    def web_login(self, redirect=None, **kw):
        from dtcloud.release import nt_service_name
        ensure_db()
        request.params['login_success'] = False
        if request.httprequest.method == 'GET' and redirect and request.session.uid:
            return request.redirect(redirect)

        # simulate hybrid auth=user/auth=public, despite using auth=none to be able
        # to redirect users when no db is selected - cfr ensure_db()
        if request.env.uid is None:
            if request.session.uid is None:
                # no user -> auth=public with specific website public user
                request.env["ir.http"]._auth_method_public()
            else:
                # auth=user
                request.update_env(user=request.session.uid)

        values = {k: v for k, v in request.params.items() if k in SIGN_UP_REQUEST_PARAMS}
        try:
            values['databases'] = http.db_list()
        except dtcloud.exceptions.AccessDenied:
            values['databases'] = None

        values['product_name'] = product_name

        if request.httprequest.method == 'POST':
            try:
                uid = request.session.authenticate(request.db, request.params['login'], request.params['password'])
                request.params['login_success'] = True
                return request.redirect(self._login_redirect(uid, redirect=redirect))
            except dtcloud.exceptions.AccessDenied as e:
                if e.args == dtcloud.exceptions.AccessDenied().args:
                    values['error'] = _("Wrong login/password")
                else:
                    values['error'] = e.args[0]
        else:
            if 'error' in request.params and request.params.get('error') == 'access':
                values['error'] = _('Only employees can access this database. Please contact the administrator.')

        if 'login' not in values and request.session.get('auth_login'):
            values['login'] = request.session.get('auth_login')

        if not dtcloud.tools.config['list_db']:
            values['disable_database_manager'] = True

        #::::查询一下
        # TODO(amos): amos write
        auth = request.env['ir.module.module'].sudo().search([('name', '=', 'auth_oauth')], limit=1)
        values['auth_oauth'] = False
        if auth:
            if auth.state == 'installed':
                values['auth_oauth'] = True

        values['csrf_token'] = request.csrf_token()
        values['session_db'] = request.session.db
        template = env.get_template('login/zh_CN/login.html')
        html = template.render(object=values)
        return html
        # response = request.render('web.login', values)
        # response.headers['X-Frame-Options'] = 'SAMEORIGIN'
        # response.headers['Content-Security-Policy'] = "frame-ancestors 'self'"
        # return response

    @http.route('/web/login_successful', type='http', auth='user', website=True, sitemap=False)
    def login_successful_external_user(self, **kwargs):
        """Landing page after successful login for external users (unused when portal is installed)."""
        valid_values = {k: v for k, v in kwargs.items() if k in LOGIN_SUCCESSFUL_PARAMS}
        return request.render('web.login_successful', valid_values)

    @http.route('/web/become', type='http', auth='user', sitemap=False)
    def switch_to_admin(self):
        uid = request.env.user.id
        if request.env.user._is_system():
            uid = request.session.uid = dtcloud.SUPERUSER_ID
            # invalidate session token cache as we've changed the uid
            request.env.registry.clear_cache()
            request.session.session_token = security.compute_session_token(request.session, request.env)

        return request.redirect(self._login_redirect(uid))

    @http.route('/web/health', type='http', auth='none', save_session=False)
    def health(self):
        data = json.dumps({
            'status': 'pass',
        })
        headers = [('Content-Type', 'application/json'),
                   ('Cache-Control', 'no-store')]
        return request.make_response(data, headers)

    @http.route(['/robots.txt'], type='http', auth="none")
    def robots(self, **kwargs):
        return "User-agent: *\nDisallow: /\n"
